
How to check whether a script is running under node.js?
up vote
74
down vote
favorite
21


I have a script I am requiring from a node.js script, which I want to keep javascript engine independent.

So, for example, I want to do:

exports.x = y;

only if it's running under node.js. how can I perform this test?

Edit: When posting this question, I didn't know the node.js modules feature is based on commonjs.

For the specific example I gave a more accurate question would've been:

How can a script tell whether it has been required as a commonjs module?
javascript node.js commonjs
shareedit

edited Nov 19 '10 at 11:52

asked Nov 19 '10 at 11:41
theosp
4,29121421

3

I've no idea why you are trying to do this, but as a rule of thumb you should be using feature detection rather then engine detection. quirksmode.org/js/support.html – Quentin Nov 19 '10 at 11:44
2

This is actually a request on how to implement feature detection, but the question poorly describes itself. – monokrome Jan 23 '13 at 21:30


published a library for my own use, help this will help npmjs.com/package/detect-is-node – abhirathore2006 Jul 31 at 6:07
add a comment
16 Answers
active
oldest
votes
up vote
55
down vote
accepted


This is how the Underscore.js library does it (by looking for CommonJS support):

Edit: to your updated question:

(function () {

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this;

    // Create a reference to this
    var _ = new Object();

    var isNode = false;

    // Export the Underscore object for **CommonJS**, with backwards-compatibility
    // for the old `require()` API. If we're not in CommonJS, add `_` to the
    // global object.
    if (typeof module !== 'undefined' && module.exports) {
            module.exports = _;
            root._ = _;
            isNode = true;
    } else {
            root._ = _;
    }
})();

Example here retains the Module pattern.
shareedit

edited Apr 27 at 16:19
Daniel
1139

answered Mar 4 '11 at 17:34
Ross
7,31484578

10

This detects CommonJS support, which browsers may support. – mikemaccana Dec 24 '12 at 14:05
4

There is a problem here and nailer "nailed it". I'm trying CommonJS in the browser, and the module loader I'm using defines module.exports, so this solution would incorrectly tell me I'm in node. – Mark Melville Dec 31 '12 at 23:02
1

@MarkMelville arguably, this is exactly what the OP is asking so therefore not a problem. – Ross Jan 1 '13 at 17:37
9

Poor wording on my part. I mean there is a problem with this solution. The OP may have accepted it, but I do not. – Mark Melville Jan 3 '13 at 23:40
2

This is most certainly NOT the best answer given. – user3751385 Nov 29 '14 at 17:53
show 2 more comments
up vote
46
down vote


Well there's no reliable way to detect running in Node.js since every website could easily declare the same variables, yet, since there's no window object in Node.js by default you can go the other way around and check whether you're running inside a Browser.

This is what I use for libs that should work both in a Browser and under Node.js:

```
if (typeof window === 'undefined') {
    exports.foo = {};

} else {
    window.foo = {};
}
```

It might still explode in case that window is defined in Node.js but there's no good reason for someone do this, since you would explicitly need to leave out var or set the property on the global object.

EDIT

For detecting whether your script has been required as a CommonJS module, that's again not easy. Only thing commonJS specifies is that A: The modules will be included via a call to the function require and B: The modules exports things via properties on the exports object. Now how that is implement is left to the underlying system. Node.js wraps the modules content in an anonymous funciton.

function (exports, require, module, __filename, __dirname) {

See: https://github.com/ry/node/blob/master/src/node.js#L325

But don't go there by trying to detect that via some crazy arguments.callee.toString() stuff, instead just use my example code above which checks for the Browser, Node.js is a way cleaner environment so it's unlikely that window will be declared there.
shareedit

edited Nov 19 '10 at 12:21
T.J. Crowder
470k76742879

answered Nov 19 '10 at 11:51
Ivo Wetzel
35k106997

1

About "Node.js is a way cleaner environment so it's unlikely that window will be declared there.": well, I just came here looking for a way to find out whether my script was running in a browser emulated by node.js + JSDOM or in a plain browser... The reason is that I have an infinite loop using setTimeout to check the URL location, which is fine in a browser, but keeps the node.js script running forever... So there might be a window in a node.js script after all :) – Eric Bréchemier Feb 1 '11 at 18:18


@Eric I highly doubt it will be there in the global scope, so unless you import something as window in the first line of your module you should not have any problems. You could also run an anonymous function and check the [[Class]] of this inside it (works only in non-strict mode) See "Class" under: bonsaiden.github.com/JavaScript-Garden/#typeof – Ivo Wetzel Feb 1 '11 at 18:28
1

My issue differs slightly from the OP's: I am not requiring the script, it is loaded by JSDOM with the emulated window as global context... It is still run by node.js + V8, just in a different context than usual modules. – Eric Bréchemier Feb 1 '11 at 20:01
1

Probably... I went another direction: 1) detect support for onhashchange ("onhashchange" in window) to avoid creating the infinite loop 2) simulate support by setting the onhashchange property on emulated window in main node.js script. – Eric Bréchemier Feb 1 '11 at 22:00
1

typeof self === 'object' might be safer since typeof window === 'undefined' fails on web workers scope. – Tresdin May 16 '15 at 10:16
show 4 more comments
up vote
17
down vote


The problem with trying to figure out what environment your code is running in is that any object can be modified and declared making it close to impossible to figure out which objects are native to the environment, and which have been modified by the program.

However, there are a few tricks we can use to figure out for sure what environment you are in.

Lets start out with the generally accepted solution that's used in the underscore library:

typeof module !== 'undefined' && module.exports

This technique is actually perfectly fine for the server side, as when the require function is called, it resets the this object to an empty object, and redefines module for you again, meaning you don't have to worry about any outside tampering. As long as your code is loaded in with require, you are safe.

However, this falls apart on the browser, as anyone can easily define module to make it seem like it's the object you are looking for. On one hand this might be the behavior you want, but it also dictates what variables the library user can use in the global scope. Maybe someone wants to use a variable with the name module that has exports inside of it for another use. It's unlikely, but who are we to judge what variables someone else can use, just because another environment uses that variable name?

The trick however, is that if we are assuming that your script is being loaded in the global scope (which it will be if it's loaded via a script tag) a variable cannot be reserved in an outer closure, because the browser does not allow that. Now remember in node, the this object is an empty object, yet, the module variable is still available. That is because it's declared in an outer closure. So we can then fix underscore's check by adding an extra check:

this.module !== module

With this, if someone declares module in the global scope in the browser, it will be placed in the this object, which will cause the test to fail, because this.module, will be the same object as module. On node, this.module does not exist, and module exists within an outer closure, so the test will succeed, as they are not equivalent.

Thus, the final test is:

typeof module !== 'undefined' && this.module !== module

Note: While this now allows the module variable to be used freely in the global scope, it is still possible to bypass this on the browser by creating a new closure and declaring module within that, then loading the script within that closure. At that point the user is fully replicating the node environment and hopefully knows what they are doing and is trying to do a node style require. If the code is called in a script tag, it will still be safe from any new outer closures.
shareedit

answered Aug 11 '12 at 23:06
TimE
1,1631119

1

Wow, thanks for clearly explaining the rationale behind each piece of your one-liner. – Jon Coombs Apr 6 '15 at 18:38
add a comment
up vote
16
down vote


The following works in the browser unless intentionally,explicitly sabotaged:

if(typeof process === 'object' && process + '' === '[object process]'){
    // is node
}
else{
    // not node
}

Bam.
shareedit

edited Dec 30 '14 at 0:09

answered Jun 18 '14 at 7:34
user3751385
58148

2

var process = { toString: function () { return '[object process]'; } }; – Nick Desaulniers Dec 29 '14 at 22:46


Is there some reason why you use process+'' instead of process.toString() ? – harmic Dec 9 '15 at 0:58
1

Almost. Use this instead: Object.prototype.toString.call(process) – Deerloper Jan 24 at 23:50


This is the best answer to this question. – loretoparisi Mar 10 at 15:18
1

@harmic: var process = null; would cause the second case to fail. In both Javascript and Java, the expression '' + x produces the same as x.toString() except when x is nasty, the former produces "null" or "undefined" where the latter would throw an error. – joeytwiddle Jun 29 at 10:20
add a comment
up vote
8
down vote


Most of the proposed solutions can actually be faked. A robust way is to check the internal Class property of the global object using the Object.prototype.toString. The internal class can't be faked in JavaScript:

var isNode =
    typeof global !== "undefined" &&
    {}.toString.call(global) == '[object global]';

shareedit

answered Aug 5 '13 at 11:53
Fabian Jakobs
11.7k52933

2

This will come back true under browserify. – alt Jan 2 '14 at 6:28
1

Did you test that? I can't see how browserify can change the internal class of an object. This would require changing code in the JavaScript VM or overwriting Object.prototype.toString which is really bad practice. – Fabian Jakobs Jan 2 '14 at 9:54


I tested it. Here's what browserify does: var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}; – Vanuan Jan 30 '14 at 15:33


You see, in Chrome, ({}.toString.call(window)) is equal "[object global]". – Vanuan Jan 30 '14 at 15:43
1

It's strange, because window.toString() produces "[object Window]" – Vanuan Jan 30 '14 at 15:45
show 1 more comment
up vote
4
down vote


I'm using process to check for node.js like so

if (typeof(process) !== 'undefined' && process.version === 'v0.9.9') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

or

if (typeof(process) !== 'undefined' && process.title === 'node') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

Documented here
shareedit

answered Apr 4 '13 at 14:14
Chris
2,3251425

1

process.title can be changed – Ben Barkay Apr 18 '13 at 23:35


Then check for the title you changed it to. Or use process.version – Chris Apr 19 '13 at 7:12


If you're writing for a library (like you should), you will not be able to expect what the title should be – Ben Barkay Apr 19 '13 at 15:57
add a comment
up vote
4
down vote


Here's my variation on what's above:

(function(publish) {
    "use strict";

    function House(no) {
        this.no = no;
    };

    House.prototype.toString = function() {
        return "House #"+this.no;
    };

    publish(House);

})((typeof module == 'undefined' || (typeof window != 'undefined' && this == window))
    ? function(a) {this["House"] = a;}
    : function(a) {module.exports = a;});

To use it, you modify the "House" on the second last line to be whatever you want the name of the module to be in the browser and publish whatever you want the value of the module to be (usually a constructor or an object literal).

In browsers the global object is window, and it has a reference to itself (there's a window.window which is == window). It seems to me that this is unlikely to occur unless you're in a browser or in an environment that wants you to believe you're in a browser. In all other cases, if there is a global 'module' variable declared, it uses that otherwise it uses the global object.
shareedit

answered Apr 13 '12 at 13:27
kybernetikos
5,0302940



+1 for: typeof window != 'undefined' && this === window – Cédric Belin May 15 '14 at 4:40
add a comment
up vote
3
down vote


    How can a script tell whether it has been required as a commonjs module?

Related: to check whether it has been required as a module vs run directly in node, you can check require.main !== module. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module
shareedit

answered Dec 5 '11 at 17:04
Pete
311



This was useful to me, thanks. – kybernetikos Mar 30 '12 at 16:29
add a comment
up vote
2
down vote


Node.js has process object, so as long as You don't have any other script which create process You can use it to determine if code runs on Node.

var isOnNodeJs = false;
if(typeof process != "undefined") {
  isOnNodeJs = true;
}

if(isOnNodeJs){
  console.log("you are running under node.js");
}
else {
  console.log("you are NOT running under node.js");
}

shareedit

edited Jan 13 '15 at 20:44

answered Jan 13 '15 at 20:33
Dariusz Sikorski
1,013519

add a comment
up vote
2
down vote


This is a pretty safe and straight-forward way of assuring compatibility between server-side and client-side javascript, that will also work with browserify, RequireJS or CommonJS included client-side:

(function(){

  // `this` now refers to `global` if we're in NodeJS
  // or `window` if we're in the browser.

}).call(function(){
  return (typeof module !== "undefined" &&
    module.exports &&
    typeof window === 'undefined') ?
    global : window;
}())

shareedit

edited Oct 16 '15 at 14:42
ggutenberg
2,84222435

answered Jul 31 '14 at 16:02
Christophe Marois
2,24011018

add a comment
up vote
2
down vote


What about using the process object and checking execPath for node?

    process.execPath

    This is the absolute pathname of the executable that started the process.

        Example:

        /usr/local/bin/node

shareedit

answered Nov 21 '10 at 14:14
Kevin Hakanson
24.1k1699133

add a comment
up vote
2
down vote


I currently stumbled over a wrong detection of Node which is not aware of the Node-environment in Electron due to a misleading feature-detection. The following solutions identify the process-environment explicitly.

Identify Node.js only

(typeof process !== 'undefined') && (process.release.name === 'node')

This will discover if you're running in a Node-process, since process.release contains the "metadata related to the current [Node-]release".

After the spawn of io.js the value of process.release.name may also become io.js (see the process-doc). To proper detect a Node-ready environment i guess you should check as follows:
Identify Node or io.js

(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)

This statement was tested with Node 5.5.0, Electron 0.36.9 (with Node 5.1.1) and Chrome 48.0.2564.116.